package com.iflytek.aisol.audit.iflytek.strategy.manage.utils;

import cn.hutool.json.JSONUtil;
import com.iflytek.aisol.audit.iflytek.strategy.manage.config.CustomException;
import com.iflytek.aisol.audit.iflytek.strategy.manage.constant.ChannelType;
import com.iflytek.aisol.audit.iflytek.strategy.manage.constant.ServerType;
import com.iflytek.aisol.audit.iflytek.strategy.manage.mapper.EngineParamMapper;
import com.iflytek.aisol.audit.iflytek.strategy.manage.constant.TableColumnInitConstant;
import com.iflytek.aisol.audit.iflytek.strategy.manage.entity.EngineParam;
import lombok.AllArgsConstructor;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

@Component
@RequiredArgsConstructor
public class ConfigValidationUtil {
    private final EngineParamMapper engineParamMapper;

    /**
     * 校验前端配置项的类型
     *
     * @param inputConfig 前端的配置config
     * @param type        类型
     */
    public <T> void validateConfig(T inputConfig, String type) {
        // 获取支持的服务类型参数
        List<EngineParam> params = engineParamMapper.findByEngineType(type);
        Map<String, String> fieldTypeMap = params.stream()
                .collect(Collectors.toMap(EngineParam::getParamName, EngineParam::getParamType));

        // 获取前端输入的 config
        String configJson = JSONUtil.toJsonStr(inputConfig);
        Map<String, Object> config = JSONUtil.toBean(configJson, Map.class);

        // 遍历配置项并校验字段
        for (Map.Entry<String, Object> entry : config.entrySet()) {
            String fieldName = entry.getKey();
            Object fieldValue = entry.getValue();
            // 获取字段的预期类型
            String expectedType = fieldTypeMap.get(fieldName);
            // 校验字段类型
            validateField(fieldName, fieldValue, expectedType,fieldTypeMap);
        }
    }

    /**
     * 递归校验字段类型
     *
     * @param fieldName    字段名称
     * @param fieldValue   字段值
     * @param expectedType 支持的类型
     */
    private static void validateField(String fieldName, Object fieldValue, String expectedType,
                                      Map<String, String> fieldTypeMap) {
        // 判断是否是 Map 类型且符合直接校验的类型
        if (fieldValue instanceof Map) {
            Map<?, ?> mapValue = (Map<?, ?>) fieldValue;
            // 判断 Map 是否符合某种预定义类型
            String mapType = inferMapType(mapValue);
            if ("map".equals(mapType)) {
                // 如果不符合类型，递归校验 Map
                for (Map.Entry<?, ?> subEntry : mapValue.entrySet()) {
                    String subFieldName = fieldName + "." + subEntry.getKey();
                    validateField(subFieldName, subEntry.getValue(), fieldTypeMap.get(subFieldName),fieldTypeMap);
                }
            }
            // 不是嵌套的map走下面
            if (!mapType.equals(expectedType) && expectedType != null) {
                throw new CustomException(TableColumnInitConstant.ERROR,
                        "字段 " + fieldName + " 类型错误，期望 " + expectedType + "，实际为 " + mapType);
            }
        } else if (fieldValue instanceof List) {
            // 如果字段是 List 类型
            List<?> listValue = (List<?>) fieldValue;
            String fieldType = inferListType(listValue);
            // 校验含嵌套的
            if("list".equals(fieldType)){
                // 遍历 List 并递归校验每个元素
                for (Object subItem : listValue) {
                    validateAggDefaultField(fieldName, subItem, expectedType, fieldTypeMap);
                }
            }
            // 不含嵌套的
            if (!fieldType.equals(expectedType) && expectedType != null) {
                throw new CustomException(TableColumnInitConstant.ERROR,
                        "字段 " + fieldName + " 类型错误，期望 " + expectedType + "，实际为 " + fieldType);
            }
        } else {
            // 基本字段类型校验
            String fieldType = inferFieldType(fieldValue);
            if (!fieldType.equals(expectedType)) {
                throw new CustomException(TableColumnInitConstant.ERROR,
                        "字段 " + fieldName + " 类型错误，期望 " + expectedType + "，实际为 " + fieldType);
            }
        }
    }
    /**
     * 专门校验 agg_default 相关字段
     */
    private static void validateAggDefaultField(String fieldName,
                                                Object fieldValue,
                                                String expectedType,
                                                Map<String, String> fieldTypeMap) {
        if (fieldValue instanceof Map) {
            for (Map.Entry<?, ?> entry : ((Map<?, ?>) fieldValue).entrySet()) {
                String subFieldName = fieldName + "." + entry.getKey();
                validateAggDefaultField(subFieldName, entry.getValue(), fieldTypeMap.get(subFieldName), fieldTypeMap);
            }
        } else if (fieldValue instanceof List) {
            for (Object subItem : (List<?>) fieldValue) {
                if (subItem instanceof Map) {
                    validateAggDefaultField(fieldName, subItem, expectedType, fieldTypeMap);
                } else {
                    String subItemType = inferFieldType(subItem);
                    if (!subItemType.equals(expectedType) && expectedType != null) {
                        throw new CustomException(TableColumnInitConstant.ERROR,
                                "字段 " + fieldName + " 类型错误，期望 " + expectedType + "，实际为 " + subItemType);
                    }
                }
            }
        }
    }

        /**
         * 判断给定的字符串是否属于 ServerType 枚举的 `type` 字段值
         *
         * @param value 要检查的字符串
         * @return 如果属于 ServerType 枚举的 type 值，则返回 true，否则返回 false
         */
        public static boolean isInServerType (String value){
            return Arrays.stream(ServerType.values())
                    .anyMatch(e -> e.getType().equals(value));
        }

        /**
         * 判断给定的字符串是否属于 ChannelType 枚举的 `type` 字段值
         *
         * @param value 要检查的字符串
         * @return 如果属于 ChannelType 枚举的 type 值，则返回 true，否则返回 false
         */
        public static boolean isInChannelType (String value){
            return Arrays.stream(ChannelType.values())
                    .anyMatch(e -> e.getType().equals(value));
        }

        /**
         * 推断字段的类型
         *
         * @param value 字段值
         * @return 推断的字段类型
         */
        private static String inferFieldType (Object value){
            if (value instanceof Double || (value instanceof Number && value.toString().contains("."))) {
                return "double";
            } else if (value instanceof Integer) {
                return "int";
            } else if (value instanceof String) {
                return "string";
            } else if (value instanceof Boolean) {
                return "boolean";
            } else if (value instanceof List) {
                return inferListType((List<?>) value);
            } else if (value instanceof Map) {
                // 尝试推断 Map 的键值类型
                return inferMapType((Map<?, ?>) value);
            }
            return "unknown";
        }

        /**
         * 推断 List 类型
         *
         * @param list List 类型
         * @return 推断的字段类型
         */
        private static String inferListType (List < ? > list) {
            if (!list.isEmpty()) {
                boolean allStrings = list.stream().allMatch(item -> item instanceof String);
                boolean allIntegers = list.stream().allMatch(item -> item instanceof Integer);
                boolean allDoubles = list.stream().allMatch(item -> item instanceof Double || (item instanceof Number && item.toString().contains(".")));

                if (allStrings) {
                    return "string[]";
                } else if (allIntegers) {
                    return "int[]";
                } else if (allDoubles) {
                    return "double[]";
                }
            }
            return "list"; // 默认返回 list 类型
        }

        /**
         * 推断 Map 类型
         *
         * @param map Map 类型
         * @return 推断的字段类型
         */
        private static String inferMapType (Map < ?, ?>map){
            if (!map.isEmpty()) {
                boolean allKeysString = map.keySet().stream().allMatch(key -> key instanceof String);

                if (allKeysString) {
                    boolean allValuesString = map.values().stream().allMatch(val -> val instanceof String);
                    boolean allValuesInt = map.values().stream().allMatch(val -> val instanceof Integer);
                    boolean allValuesDouble = map.values().stream().allMatch(val -> val instanceof Double || (val instanceof Number && val.toString().contains(".")));
                    boolean allValuesBoolean = map.values().stream().allMatch(val -> val instanceof Boolean);

                    if (allValuesString) {
                        return "map<string,string>";
                    } else if (allValuesInt) {
                        return "map<string,int>";
                    } else if (allValuesDouble) {
                        return "map<string,double>";
                    } else if (allValuesBoolean) {
                        return "map<string,boolean>";
                    }
                }
            }
            return "map"; // 默认返回 map 类型
        }
    }